package edu.sjb.gui;

import java.awt.Dimension;
import java.awt.Toolkit;
import java.util.ArrayList;
import java.util.HashMap;

import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.WindowConstants;

import edu.sjb.AppLauncher;
import edu.sjb.Drawable;
import edu.sjb.characters.GameCharacter;
import edu.sjb.characters.Mario;
import edu.sjb.constants.ImageConstants;
import edu.sjb.map.GameEntity;
import edu.sjb.map.Level;
import edu.sjb.map.MapObject;
import edu.sjb.map.prizes.PowerUp;
import edu.sjb.threads.SoundThread;

@SuppressWarnings("serial")
public class GameScreen extends javax.swing.JFrame implements Runnable {
	private static final int refreshLocation = 400;

	protected ArrayList<GameCharacter> gameCharacters;
	protected ArrayList<PowerUp> powerUps;
	protected Level level;
	protected Drawable background;
	protected Thread gameThread;
	protected Thread gravityThread;
	protected HashMap<GameEntity, Thread> enemiesThreads;
	protected SoundThread sfxThread;
	protected GameScreenKeyListener keyboardListener;
	protected boolean active;
	protected boolean marioDied;
	private long delta;
	private JPanel backgroundPanel;
	protected int score;
	protected int lives;
	private JLabel scoreLabel;
	private JLabel livesLabel;

	public GameScreen(Level nivelActual) {
		super("Super JAVA Bros");
		this.level = nivelActual;
		score = 0;
		lives = 1;
		start();
		initGUI();
		gameThread = new Thread(this);
		gameThread.start();
	}

	private void start() {
		gameCharacters = new ArrayList<GameCharacter>();
		powerUps = new ArrayList<PowerUp>();
		enemiesThreads = new HashMap<GameEntity, Thread>();
		Mario baseMario = new Mario();
		Mario gameMario = (Mario) baseMario.clonate();
		gameMario.setPosX(100);
		gameMario.setPosY(512);
		gameMario.setSizeX(32);
		gameMario.setSizeY(32);
		gameMario.image().setBounds(gameMario.posX(), gameMario.posY(), 32, 32);
		gameMario.goStart();
		gameMario.setGameContext(this);
		keyboardListener = new GameScreenKeyListener(gameMario);
		marioDied = false;
		level.addMario(gameMario);
		sfxThread = new SoundThread();
		SoundThread.startBGMOverworld();
		active = true;
	}

	private void initGUI() {
		try {
			{
				backgroundPanel = new JPanel();
				getContentPane().add(backgroundPanel);
				backgroundPanel.setLayout(null);
				backgroundPanel.setBackground(new java.awt.Color(0, 0, 0));
				backgroundPanel.setSize(800, 600);
				backgroundPanel.setBounds(0, 0, 800, 600);
			}
			{
				backgroundPanel.add(level.mario().image());
				level.mario().image().setSize(32, 32);
			}
			{
				scoreLabel = new JLabel("Puntaje: " + score);
				scoreLabel.setBounds(600, 0, 200, 100);
				backgroundPanel.add(scoreLabel);
				scoreLabel.setFont(new java.awt.Font("Arial Black", 0, 20));
			}
			{
				livesLabel = new JLabel("Vidas: " + lives);
				livesLabel.setBounds(400, 0, 200, 100);
				backgroundPanel.add(livesLabel);
				livesLabel.setFont(new java.awt.Font("Arial Black", 0, 20));
			}
			{
				entitiesSetup();
			}
			{
				background = new Drawable(ImageConstants.BACKGROUND, false);
				background.setSize(8772, 609);
				background.setBounds(0, 0, 8772, 609);
				backgroundPanel.add(background);
				this.setFocusable(true);
				setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
				pack();

				Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
				int x = (screen.width - 800) / 2;
				int y = (screen.height - 627) / 2;
				setBounds(x, y, 800, 627);
				setIgnoreRepaint(true);
				setResizable(false);
				addKeyListener(keyboardListener);
				setVisible(true);
			}
		}
		catch (Exception e) {
		}
	}

	private void entitiesSetup() {

		GameCharacter tempCharacter = null;
		MapObject tempObject = null;
		PowerUp tempPowerUp = null;
		for (int i = 1; i < level.characterCollection().size(); i++) {
			tempCharacter = level.characterCollection().get(i);
			tempCharacter.setGameContext(this);
			backgroundPanel.add(tempCharacter.image());
			enemiesThreads.put(tempCharacter, new Thread(tempCharacter));
			enemiesThreads.get(tempCharacter).start();
		}
		for (int i = 0; i < level.objectCollection().size(); i++) {
			tempObject = level.objectCollection().get(i);
			tempObject.setGameContext(this);
			backgroundPanel.add(tempObject.image());
		}
		for (int i = 0; i < level.powerupCollection().size(); i++) {
			tempPowerUp = level.powerupCollection().get(i);
			tempPowerUp.setGameContext(this);
			backgroundPanel.add(tempPowerUp.image());
		}
	}

	public void run() {
		long lastLoopTime = System.currentTimeMillis();
		while (active) {
			delta = System.currentTimeMillis() - lastLoopTime;
			lastLoopTime = System.currentTimeMillis();
			GameEntity current = null;
			if (keyboardListener.canMoveRight()) {
				if (background.getX() > -7744) {
					level.mario().walkRight();
					if (level.mario().posX() >= refreshLocation) {
						if (keyboardListener.canRun()) {
							background
							        .setLocation(
							                (int) (background.getX() - ((delta * 37) / 100)),
							                background.getY());
						}
						else {
							background
							        .setLocation(
							                (int) (background.getX() - ((delta * 22) / 100)),
							                background.getY());
						}
						for (int i = 1; i < level.characterCollection().size(); i++) {
							current = level.characterCollection().get(i);
							current.shiftPosX(-delta);
						}
						for (int i = 0; i < level.objectCollection().size(); i++) {
							current = level.objectCollection().get(i);
							current.shiftPosX(-delta);
						}
						for (int i = 0; i < level.powerupCollection().size(); i++) {
							current = level.powerupCollection().get(i);
							current.shiftPosX(-delta);
						}
					}
					else {
						level.mario().shiftPosX(+delta);
					}
				}
				else {
					marioDied = false;
					clearedGame();
				}
			}
			if (keyboardListener.canMoveLeft()) {

				if (level.mario().posX() > 0) {
					level.mario().walkLeft();
					level.mario().shiftPosX(-delta);
				}
				else {
					level.mario().stopLeft();
				}
			}
			if (keyboardListener.canJump()) {
				level.mario().action1();
			}
			for (int i = 1; i < level.characterCollection().size(); i++) {
				current = level.characterCollection().get(i);
				if (level.mario().collides(current)) {
					current.hitAgainstMario(level.mario());
				}
			}
			for (int i = 0; i < level.objectCollection().size(); i++) {
				current = level.objectCollection().get(i);
				if (level.mario().collides(current)) {
					current.hitAgainstMario(level.mario());
				}
			}
			for (int i = 0; i < level.powerupCollection().size(); i++) {
				current = level.powerupCollection().get(i);
				if (level.mario().collides(current)
				        && (!current.image().isHidden())) {
					current.hitAgainstMario(level.mario());
				}
			}
			for (int i = 1; i < level.characterCollection().size(); i++) {
				for (int j = i + 1; j < level.characterCollection().size(); j++) {
					if (level.characterCollection().get(i)
					        .collides(level.characterCollection().get(j))) {
						level.characterCollection()
						        .get(i)
						        .characterCollide(
						                level.characterCollection().get(j));
					}
				}
			}
			for (int i = 1; i < level.characterCollection().size(); i++) {
				for (int j = 0; j < level.objectCollection().size(); j++) {
					if (level.characterCollection().get(i)
					        .collides(level.objectCollection().get(j))) {
						level.objectCollection()
						        .get(j)
						        .characterCollide(
						                level.characterCollection().get(i));
					}
				}
			}
			if ((level.mario().gravity().onAir())
			        && (!level.mario().underMushroomEffect())) {
				gravityThread = new Thread(level.mario().gravity());
				gravityThread.start();

			}
			for (int i = 0; i < level.characterCollection().size(); i++) {
				current = level.characterCollection().get(i);
				current.dibujar(getGraphics());
			}
			for (int i = 0; i < level.objectCollection().size(); i++) {
				current = level.objectCollection().get(i);
				current.dibujar(getGraphics());
			}
			for (int i = 0; i < level.powerupCollection().size(); i++) {
				current = level.powerupCollection().get(i);
				current.dibujar(getGraphics());
			}
			scoreLabel.setText("Puntaje: " + score);
			livesLabel.setText("Vidas: " + lives);
			level.characterCollection().removeAll(gameCharacters);
			gameCharacters.clear();
			level.powerupCollection().removeAll(powerUps);
			powerUps.clear();
			background.repaint();
			try {
				Thread.sleep(10);
			}
			catch (InterruptedException e) {
			}
		}
	}

	public void changeScore(int puntaje) {

		this.score += puntaje;
	}

	public void gain1UP() {
		lives++;
	}

	public void marioDied() {
		level.mario().setCanGoRight(false);
		level.mario().setCanGoLeft(false);
		level.mario().setCanJump(false);
		marioDied = true;
		SoundThread.stopBGMOverworld();
		SoundThread.startBGMDead();
		gravityThread = new Thread(level.mario().gravity());
		gravityThread.start();
	}

	private void reset() {
		marioDied = false;
		level.mario().goStart();
		SoundThread.stopBGMDead();
		SoundThread.startBGMOverworld();
		level.mario().setCanGoRight(true);
		level.mario().setCanGoLeft(true);
		level.mario().setCanJump(true);
		level.mario().setPosX(level.mario().posX() - 64);
		level.mario().setPosY(544 - level.mario().sizeY());
	}

	public void clearedGame() {
		SoundThread.stopBGMOverworld();
		SoundThread.startBGMGoal();
		level.mario().setCanGoRight(false);
		level.mario().setCanGoLeft(false);
		level.mario().setCanJump(false);
		Thread castle = new Thread(level.mario());
		castle.start();
	}

	public void finishGame() {
		if (active) {
			if (lives > 0 && marioDied) {
				lives--;
				try {
					Thread.sleep(3000);
				}
				catch (InterruptedException e) {
				}
				reset();
			}
			else {
				active = false;
				gameThread = null;
				JOptionPane.showMessageDialog(null, "¡Juego terminado!\n"
				        + "Puntaje final: " + score, AppLauncher.APPNAME,
				        JOptionPane.INFORMATION_MESSAGE);
				int chosen = JOptionPane
				        .showConfirmDialog(this, "¿Reiniciar el mismo nivel?",
				                AppLauncher.APPNAME, JOptionPane.YES_NO_OPTION,
				                JOptionPane.QUESTION_MESSAGE);
				if (chosen == JOptionPane.YES_OPTION) {
					StartScreen ss = new StartScreen();
					ss.setVisible(true);
					ss.setLocationRelativeTo(null);
					this.dispose();
				}
				else {
					JOptionPane.showMessageDialog(null, "¡Gracias por jugar "
					        + AppLauncher.APPNAME + "!", AppLauncher.APPNAME,
					        JOptionPane.INFORMATION_MESSAGE);
					System.exit(0);
				}
			}
		}
	}

	public void removeEntity(GameCharacter gc) {
		enemiesThreads.remove(gc);
		backgroundPanel.remove(gc.image());
		gameCharacters.add(gc);
	}

	public void removerPowerUp(PowerUp item, boolean g) {
		if (!g) {
			powerUps.add(item);
		}
		backgroundPanel.remove(item.image());

	}

	public ArrayList<GameCharacter> getCharacters() {
		return level.characterCollection();
	}

	public ArrayList<MapObject> getObjects() {
		return level.objectCollection();
	}

	public ArrayList<PowerUp> getPowerUps() {
		return level.powerupCollection();
	}

	public Mario mario() {
		return level.mario();
	}

	public boolean isMarioDead() {
		return marioDied;
	}
}
